use base64::{engine::general_purpose, Engine};
use serde_json::Value;
use uuid::Uuid;

use crate::policy_error::policy_error::PolicyError;

pub struct ParameterFilter;

impl ParameterFilter {
    /// Validate policy request parameters
    pub fn validate_policy_request(
        request_body: &Value,
        required_fields: &[&str],
    ) -> Result<(), PolicyError> {
        Self::validate_required_fields(request_body, required_fields)?;
        Self::validate_request_body(request_body)?;
        
        // 定义字段验证规则映射
        let field_validators: Vec<(&str, fn(&Value, &str) -> Result<(), PolicyError>)> = vec![
            ("id", |body, field| Self::validate_uuid_field(body, field)),
            ("name", |body, field| Self::validate_string_field(body, field, 255, true)),
            ("description", |body, field| Self::validate_string_field(body, field, 512, false)),
            ("attester_type", |body, field| Self::validate_string_array_field(body, field)),
            ("content_type", |body, _field| Self::validate_content_type_field(body)),
            ("content", |body, _field| Self::validate_content_field(body)),
            ("is_default", |body, field| Self::validate_boolean_field(body, field)),
            ("ids", |body, field| Self::validate_uuid_array_field(body, field)),
            ("delete_type", |body, _field| Self::validate_delete_type_field(body)),
        ];

        // 遍历验证规则并执行验证
        for (field, validator) in field_validators {
            if request_body.get(field).is_some() {
                validator(request_body, field)?;
            }
        }
        
        Ok(())
    }
    
    fn validate_required_fields(request_body: &Value, required_fields: &[&str]) -> Result<(), PolicyError> {
        for field in required_fields.iter() {
            if !request_body.get(*field).is_some() {
                return Err(PolicyError::IncorrectFormatError(format!("Missing required parameter: {}", field).into()));
            }
        }
        Ok(())
    }

    fn validate_request_body(request_body: &Value) -> Result<(), PolicyError> {
        let allowed_fields = ["name", "description", "attester_type", "content_type", 
                            "content", "is_default", "id", "ids", "delete_type"];
        if let Some(obj) = request_body.as_object() {
            for key in obj.keys() {
                if !allowed_fields.contains(&key.as_str()) {
                    return Err(PolicyError::IncorrectFormatError(
                        format!("Unsupported parameter: {}", key)
                    ));
                }
            }
        }
        Ok(())
    }

    /// Validate string field
    fn validate_string_field(request_body: &Value, field_name: &str, max_length: usize, disallow_empty: bool) -> Result<(), PolicyError> {
        let field = request_body.get(field_name).unwrap();
        
        if !field.is_string() {
            return Err(PolicyError::IncorrectFormatError(format!("{} must be a string", field_name).into()));
        }
        
        let field_str = field.as_str().unwrap();
        if (disallow_empty && field_str.is_empty()) || field_str.len() > max_length || Self::contains_special_chars(field_str) {
            return Err(PolicyError::IncorrectFormatError(format!("{} contains invalid characters or exceeds length limit", field_name).into()));
        }
        
        Ok(())
    }

    /// Validate string array field
    fn validate_string_array_field(request_body: &Value, field_name: &str) -> Result<(), PolicyError> {
        let field = request_body.get(field_name).unwrap();
        
        if !field.is_array() && !field.is_string() {
            return Err(PolicyError::IncorrectFormatError(format!("{} must be an array or string", field_name).into()));
        }
        if field.is_array() {
            let array = field.as_array().unwrap();
            if array.is_empty() {
                return Err(PolicyError::IncorrectFormatError(format!("{} cannot be empty", field_name).into()));
            }
            
            for item in array {
                if !item.is_string() {
                    return Err(PolicyError::IncorrectFormatError(format!("{} items must be strings", field_name).into()));
                }
                
                let item_str = item.as_str().unwrap();
                if item_str.is_empty() || Self::contains_special_chars(item_str) {
                    return Err(PolicyError::IncorrectFormatError(format!("{} contains invalid characters", field_name).into()));
                }
            }
        } else {
            let field_str = field.as_str().unwrap();
            if field_str.len() > 255 || Self::contains_special_chars(field_str) {
                return Err(PolicyError::IncorrectFormatError(format!("{} contains invalid characters or exceeds length limit", field_name).into()));
            }
        }
        
        Ok(())
    }

    /// Validate boolean field
    fn validate_boolean_field(request_body: &Value, field_name: &str) -> Result<(), PolicyError> {
        let field = request_body.get(field_name).unwrap();
        
        if !field.is_boolean() {
            return Err(PolicyError::IncorrectFormatError(format!("{} must be a boolean", field_name).into()));
        }
        
        Ok(())
    }

    /// Validate UUID array field
    fn validate_uuid_array_field(request_body: &Value, field_name: &str) -> Result<(), PolicyError> {
        let field = request_body.get(field_name).unwrap();
        
        if !field.is_array() {
            return Err(PolicyError::IncorrectFormatError(format!("{} must be an array", field_name).into()));
        }
        
        let array = field.as_array().unwrap();
        if array.is_empty() {
            return Err(PolicyError::IncorrectFormatError(format!("{} cannot be empty", field_name).into()));
        }
        
        for item in array {
            if !item.is_string() {
                return Err(PolicyError::IncorrectFormatError(format!("{} items must be strings", field_name).into()));
            }
            
            let id_str = item.as_str().unwrap();
            if let Err(_) = Uuid::parse_str(id_str) {
                return Err(PolicyError::IncorrectFormatError(format!("invalid UUID format: {}", id_str).into()));
            }
        }
        
        Ok(())
    }

    /// Validate content_type field
    fn validate_content_type_field(request_body: &Value) -> Result<(), PolicyError> {
        let content_type = request_body.get("content_type").unwrap();
        
        if !content_type.is_string() {
            return Err(PolicyError::IncorrectFormatError("content_type must be a string".into()));
        }
        
        let content_type_str = content_type.as_str().unwrap();
        match content_type_str {
            "jwt" | "text" => Ok(()),
            _ => Err(PolicyError::IncorrectFormatError("content_type must be either 'jwt' or 'text'".into()))
        }
    }

    /// Validate content field
    fn validate_content_field(request_body: &Value) -> Result<(), PolicyError> {
        let content = request_body.get("content").unwrap();
        
        if !content.is_string() {
            return Err(PolicyError::IncorrectFormatError("content must be a string".into()));
        }
        
        let content_str = content.as_str().unwrap();
        if content_str.is_empty() {
            return Err(PolicyError::IncorrectFormatError("content cannot be empty".into()));
        }
        
        // When content_type is text, validate Base64 encoding
        if let Some(content_type) = request_body.get("content_type") {
            if content_type.is_string() && content_type.as_str().unwrap() == "text" {
                if let Err(_) = general_purpose::STANDARD.decode(content_str) {
                    return Err(PolicyError::IncorrectFormatError("content must be Base64 encoded".into()));
                }
            }
        }
        
        // If content_type is jwt, also validate JWT format
        if let Some(content_type) = request_body.get("content_type") {
            if content_type.is_string() && content_type.as_str().unwrap() == "jwt" {
                Self::validate_jwt_content(content_str)?
            }
        }
        
        Ok(())
    }

    /// Check if string contains special characters
    fn contains_special_chars(s: &str) -> bool {
        // Define disallowed special characters
        let special_chars = ['<', '>', '"', '\'', '&', '|', '\\', '/', '*', '?', '`'];
        s.chars().any(|c| special_chars.contains(&c))
    }

    /// Validate JWT field
    fn validate_jwt_fields(json: &Value, field: &str, section: &str) -> Result<(), PolicyError> {
        if !json.get(field).is_some() {
            return Err(PolicyError::IncorrectFormatError(format!("JWT {} must contain '{}' field", section, field).into()));
        }
        Ok(())
    }

    /// Validate UUID field
    fn validate_uuid_field(request_body: &Value, field_name: &str) -> Result<(), PolicyError> {
        let field = request_body.get(field_name).unwrap();
        
        if !field.is_string() {
            return Err(PolicyError::IncorrectFormatError(format!("{} must be a string", field_name).into()));
        }
        
        let id_str = field.as_str().unwrap();
        if let Err(_) = Uuid::parse_str(id_str) {
            return Err(PolicyError::IncorrectFormatError(format!("invalid UUID format: {}", id_str).into()));
        }
        
        Ok(())
    }

    /// Validate query parameters
    pub fn validate_query_params(query_params: &Value) -> Result<(), PolicyError> {
        if !query_params.is_object() {
            return Err(PolicyError::IncorrectFormatError("Query parameters must be an object".to_string()));
        }
        let obj = query_params.as_object().unwrap();
        if obj.len() > 0 {
            for key in obj.keys() {
                if key != "ids" && key != "attester_type" {
                    return Err(PolicyError::IncorrectFormatError(format!("Unsupported query parameter: {}", key)));
                }
            }
        }
        Ok(())
    }

    /// Validate delete_type field for 'id' type
    fn validate_id_delete_type(request_body: &Value) -> Result<(), PolicyError> {
        // Check if ids field exists when delete_type is "id"
        if !request_body.get("ids").is_some() {
            return Err(PolicyError::IncorrectFormatError("ids field is required when delete_type is 'id'".into()));
        }
        
        // Check if ids array length is not more than 10
        let ids = request_body.get("ids").unwrap().as_array().unwrap();
        if ids.len() > 10 {
            return Err(PolicyError::IncorrectFormatError("ids field cannot contain more than 10 items".into()));
        }

        // Check if there are any other fields when delete_type is "id"
        let fields: Vec<&str> = request_body.as_object().unwrap().keys()
            .map(|k| k.as_str())
            .filter(|&k| k != "delete_type" && k != "ids")
            .collect();
        
        if !fields.is_empty() {
            return Err(PolicyError::IncorrectFormatError("when delete_type is 'id', only delete_type and ids fields are allowed".into()));
        }
        Ok(())
    }

    /// Validate delete_type field for 'attester_type' type
    fn validate_attester_type_delete_type(request_body: &Value) -> Result<(), PolicyError> {
        // Check if attester_type field exists when delete_type is "attester_type"
        if !request_body.get("attester_type").is_some() {
            return Err(PolicyError::IncorrectFormatError("attester_type field is required when delete_type is 'attester_type'".into()));
        }

        // Check if there are any other fields when delete_type is "attester_type"
        let fields: Vec<&str> = request_body.as_object().unwrap().keys()
            .map(|k| k.as_str())
            .filter(|&k| k != "delete_type" && k != "attester_type")
            .collect();
        
        if !fields.is_empty() {
            return Err(PolicyError::IncorrectFormatError("when delete_type is 'attester_type', only delete_type and attester_type fields are allowed".into()));
        }
        Ok(())
    }

    /// Validate delete_type field for 'all' type
    fn validate_all_delete_type(request_body: &Value) -> Result<(), PolicyError> {
        // Check if there are any other fields when delete_type is "all"
        let fields: Vec<&str> = request_body.as_object().unwrap().keys()
            .map(|k| k.as_str())
            .filter(|&k| k != "delete_type")
            .collect();
        
        if !fields.is_empty() {
            return Err(PolicyError::IncorrectFormatError("when delete_type is 'all', no other fields are allowed".into()));
        }
        Ok(())
    }

    /// Validate delete_type field
    fn validate_delete_type_field(request_body: &Value) -> Result<(), PolicyError> {
        let delete_type = request_body.get("delete_type").unwrap();
        
        if !delete_type.is_string() {
            return Err(PolicyError::IncorrectFormatError("delete_type must be a string".into()));
        }
        
        let delete_type_str = delete_type.as_str().unwrap();
        match delete_type_str {
            "id" => Self::validate_id_delete_type(request_body),
            "attester_type" => Self::validate_attester_type_delete_type(request_body),
            "all" => Self::validate_all_delete_type(request_body),
            _ => Err(PolicyError::IncorrectFormatError("delete_type must be either 'id', 'attester_type' or 'all'".into()))
        }
    }

    /// Validate JWT content
    fn validate_jwt_content(jwt_content: &str) -> Result<(), PolicyError> {
        let parts: Vec<&str> = jwt_content.split('.').collect();
        if parts.len() != 3 {
            return Err(PolicyError::IncorrectFormatError("JWT must have three parts separated by dots".into()));
        }

        let header_json = match general_purpose::STANDARD_NO_PAD.decode(parts[0]) {
            Ok(decoded) => match String::from_utf8(decoded) {
                Ok(text) => match serde_json::from_str::<Value>(&text) {
                    Ok(json) => json,
                    Err(_) => return Err(PolicyError::IncorrectFormatError("JWT header is not valid JSON".into()))
                },
                Err(_) => return Err(PolicyError::IncorrectFormatError("JWT header is not valid UTF-8".into()))
            },
            Err(_) => return Err(PolicyError::IncorrectFormatError("Invalid JWT header".into()))
        };
        Self::validate_jwt_fields(&header_json, "alg", "header")?;
        Self::validate_jwt_fields(&header_json, "kid", "header")?;

        // Validate payload section
        let payload_json = match general_purpose::STANDARD_NO_PAD.decode(parts[1]) {
            Ok(decoded) => match String::from_utf8(decoded) {
                Ok(text) => match serde_json::from_str::<Value>(&text) {
                    Ok(json) => json,
                    Err(_) => return Err(PolicyError::IncorrectFormatError("JWT payload is not valid JSON".into()))
                },
                Err(_) => return Err(PolicyError::IncorrectFormatError("JWT payload is not valid UTF-8".into()))
            },
            Err(_) => return Err(PolicyError::IncorrectFormatError("Invalid JWT payload".into()))
        };
        Self::validate_jwt_fields(&payload_json, "policy", "payload")?;

        Ok(())
    }
}